package com.lagou.edu.service.impl;

import com.lagou.edu.dao.AccountDao;
import com.lagou.edu.dao.impl.JdbcAccountDaoImpl;
import com.lagou.edu.factory.BeanFactory;
import com.lagou.edu.pojo.Account;
import com.lagou.edu.service.TransferService;
import com.lagou.edu.utils.ConnectionUtils;
import com.lagou.edu.utils.TransactionManager;

public class TransferServiceImpl implements TransferService {

    /**
     * 问题分析
     * 问题一：new关键字将service层的实现类TransferServiceImpl和Dao层的具体实现类JdbcAccountDaoImpl耦合在了一起，
     * 当需要切换Dao层实现类时必须得修改service代码，不符合面向接口开发的最优原则
     * <p>
     * 问题二：service层没有添加事务控制，出现异常可能导致数据错乱，问题很严重，尤其在金融银行行业
     * <p>
     * 问题一思考：
     * （1）new关键字在实例化对象，除了new以外还有什么技术可以实例化对象（反射）
     * Class.forName("全限定类名") com.lagou.edu.dao.JdbcAccountDaoImpl
     * 可以把全限定类名配置在xml中
     * （2）使用工厂来通过反射技术生产对象，工厂模式是解耦合非常好的一种方式
     * <p>
     * 问题二分析：
     * 数据库事务归根结底是connection事务，connection.commit()提交事务，connection.rollback()回滚事务
     * （1）两次update使用两个数据库连接connection，这样的话肯定是不属于一个事务控制了
     * （2）事务控制目前在dao层进行，没有控制在service层
     * <p>
     * 问题二思路：
     * （1）让两次update使用同一个connection连接：两次update属于同一个线程内的执行调用，我们可以给当前线程绑定一个connection，
     * 和当前线程有关系的数据库操作都去使用这个connection（从当前线程中去拿）
     * （2）把事务控制添加在service层
     */
    // new实例化对象
    //private AccountDao accountDao = new JdbcAccountDaoImpl();

    // new关键字耦合问题改造一.工厂模式通过解析xml，反射来实例化对象
    //private AccountDao accountDao = (AccountDao)BeanFactory.getBean("accountDao");

    // new关键字耦合问题改造二(最佳状态).实例化对象完成后，维护对象依赖关系：通过构造函数/set方法来给对象赋值
    private AccountDao accountDao;

    public void setAccountDao(AccountDao accountDao) {
        this.accountDao = accountDao;
    }

    @Override
    public void transfer(String fromCardNo, String toCardNo, int money) throws Exception {
        // 动态代理改造事务控制
        /*try {
            // 开启事务(关闭事务的自动提交)
            TransactionManager.getInstance().beginTransaction();*/

            Account from = accountDao.queryAccountByCardNo(fromCardNo);
            Account to = accountDao.queryAccountByCardNo(toCardNo);

            from.setMoney(from.getMoney() - money);
            to.setMoney(to.getMoney() + money);

            accountDao.updateAccountByCardNo(to);
            int c = 1/0;
            accountDao.updateAccountByCardNo(from);

            // 动态代理改造事务控制
            /*// 提交事务
            TransactionManager.getInstance().commit();
        } catch (Exception e) {
            e.printStackTrace();
            // 回滚事务
            TransactionManager.getInstance().rollback();
            // 抛出异常便于上层servlet捕获
            throw e;
        }*/
    }
}
